{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# 1.特征检测\n",
    "## 1.1 SURF特征检测\n",
    "注意，OpenCV 3.0版本中，SURF特征匹配的函数已经被移除。可以尝试使用低版本的OpenCV或额外编译opencv_contib模块来运行以下代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "img = cv.imread(\"../images/lena.png\")\n",
    "#创建SURF描述子\n",
    "surf = cv.xfeatures2d.SURF_create(7000)\n",
    "\n",
    "kp, des = surf.detectAndCompute(img,None)\n",
    "\n",
    "img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4)\n",
    "while True:\n",
    "    cv.imshow('surf',img2)\n",
    "    key=cv.waitKey(10)\n",
    "    #监听按键q退出,s保存\n",
    "    if key==ord('q'):\n",
    "        break\n",
    "    if key==ord('s'):\n",
    "\t    cv.imwrite('surfFM.png',img2)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.2 FAST特征检测\n",
    "FAST（Feature from Accelerated Segment Test）相对于SURF的速度提升效果十分明显，可以做到特征的实时检测。FAST不计算描述子，只检测特征点。其原理是提取图像中的点，判断以该点为圆心的周围领域内像素点和该点有多不同，来判断该点是否是角点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img = cv.imread(r'../images/lena.png')  \n",
    "\n",
    "#创建fast对象，进行极大值抑制\n",
    "fast = cv.FastFeatureDetector_create(threshold=30)     \n",
    "#进行检测\n",
    "kp = fast.detect(img, None)                           \n",
    "img1 = img.copy()   \n",
    "#绘制keypoint                                    \n",
    "img1 = cv.drawKeypoints(img1, kp, None, color=(0,0,255))\n",
    "\n",
    "while True:\n",
    "    cv.imshow('fast',img1)\n",
    "    key=cv.waitKey(10)\n",
    "    #监听按键q退出,s保存\n",
    "    if key==ord('q'):\n",
    "        break\n",
    "    if key==ord('s'):\n",
    "\t    cv.imwrite('fastFM.png',img1)\n",
    "cv.destroyAllWindows()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.3 ORB特征检测\n",
    "由于FAST检测值检测特征点不计算描述子，所以特征点也不带方向。Oriented FAST是在FAST的基础上加了特征点的方向，BRIEf是另一种特征检测算法，该算法对已检测到的特征点进行描述，需配合特征点检测算法一起使用，其对图像旋转的检测有很大局限。ORB是对FAST和BRIEF进行改进后再结合到一起的技术。ORB最大的优势是可以做到实时检测。ORB主要对数据量进行了缩减。对图像进行区域划分，抛弃一些没有必要的点，计算描述子时也抛弃了大量的数据。对于大规模的图像特征点检测场景有更高的效率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "500\n"
     ]
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img = cv.imread('../images/lena.png') \n",
    "#创建orb对象\n",
    "orb = cv.ORB_create()             \n",
    "#进行检测                     \n",
    "kp, des = orb.detectAndCompute(img, None)               \n",
    "\n",
    "img1 = img.copy()               \n",
    "#绘制keypoint                        \n",
    "img1 = cv.drawKeypoints(img1, kp, None, color=(0, 0, 255))     \n",
    "print(len(kp))  \n",
    "\n",
    "while True:\n",
    "    cv.imshow('fast',img1)\n",
    "    key=cv.waitKey(10)\n",
    "    #监听按键q退出,s保存\n",
    "    if key==ord('q'):\n",
    "        break\n",
    "    if key==ord('s'):\n",
    "\t    cv.imwrite('orbFM.png',img1)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2 特征匹配"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "\n",
    "# 读取图片\n",
    "img1 = cv.imread(\"../images/lena.png\")\n",
    "gray1 = cv.cvtColor(src=img1, code=cv.COLOR_BGR2GRAY)\n",
    "\n",
    "img2 = cv.imread(\"../images/flann.jpg\")\n",
    "img2 = cv.resize(src=img2, dsize=(1040, 780))\n",
    "gray2 = cv.cvtColor(src=img2, code=cv.COLOR_BGR2GRAY)\n",
    "\n",
    "# 创建SIFT描述子\n",
    "sift = cv.SIFT_create()\n",
    "kp1, des1 = sift.detectAndCompute(img1, None)\n",
    "kp2, des2 = sift.detectAndCompute(img2, None)\n",
    "\n",
    "# 使用KDTREE算法，树的层级使用5\n",
    "index_params = dict(algorithm=1, trees=5)\n",
    "search_params = dict(checks=50)\n",
    "# 创建匹配器\n",
    "flann = cv.FlannBasedMatcher(index_params, search_params)\n",
    "# 特征点匹配\n",
    "matches = flann.knnMatch(des1, des2, k=2)\n",
    "\n",
    "# 筛选出较好的匹配点\n",
    "good = []\n",
    "for m, n in matches:\n",
    "    if m.distance < 0.7 * n.distance:\n",
    "        good.append([m])\n",
    "\n",
    "# 绘制匹配特征点\n",
    "dest = cv.drawMatchesKnn(img1, kp1, img2, kp2, good, None, matchColor=(0, 255, 0))\n",
    "\n",
    "while True:\n",
    "    cv.imshow('dest', dest)\n",
    "    key = cv.waitKey(10)\n",
    "    # 监听按键q退出, s保存\n",
    "    if key == ord('q'):\n",
    "        break\n",
    "    if key == ord('s'):\n",
    "        cv.imwrite('flann.png', img2)\n",
    "cv.destroyAllWindows()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
